﻿using System;
using System.Collections.Generic;
using System.Reflection;
using MugenInjection.Interface;
using MugenInjection.Web;

namespace MugenInjection.Wcf.Service
{
    /// <summary>
    ///  Base class providing easy access to <see cref="IInjectorResolver"/>.
    /// </summary>
    public abstract class MugenInjectionServiceBase : IInjectorResolver
    {
        #region Implementation of IInjectorResolver

        /// <summary>
        /// Create <see cref="IBindingContext"/> for current <see cref="IInjectorBinder"/>.
        /// </summary>
        /// <param name="service">Service for resolve.</param>
        /// <param name="member"><see cref="System.Reflection.MemberInfo"/> when injected specified service. Can be null.</param>
        /// <param name="parameterInfo"><see cref="System.Reflection.ParameterInfo"/> when injected specified service. Can be null.</param>
        /// <param name="parameters">Parameters for service.</param>
        /// <param name="specialParameters">Special parameters for resolve specified service.</param>
        /// <returns>The created <see cref="IBindingContext"/>.</returns>
        public IBindingContext CreateContext(Type service, MemberInfo member, ParameterInfo parameterInfo,
                                             IEnumerable<IInjectionParameter> parameters,
                                             IDictionary<string, object> specialParameters)
        {
            return GetInjectorResolver().CreateContext(service, member, parameterInfo, parameters, specialParameters);
        }

        /// <summary>
        /// Injects property, method, fields in specified object.
        /// </summary>
        /// <param name="target">The specified object for inject.</param>
        /// <param name="bindingContext"> The specified <see cref="IBindingContext"/>.</param>
        public void Inject<T>(ref T target, IBindingContext bindingContext)
        {
            GetInjectorResolver().Inject(ref target, bindingContext);
        }


        /// <summary>
        /// Determines whether the specified request can be resolved.
        /// </summary>
        /// <param name="bindingContext"> The specified <see cref="IBindingContext"/>.</param>
        /// <param name="searchInParent">If set to <c>true</c> search in parent bindings.</param>
        /// <param name="includeImplicitBindings">If set to <c>false</c> implicit bindings are ignored.</param>
        /// <returns><c>True</c> if the specified service has been resolved; otherwise, <c>false</c>.</returns>
        public bool CanResolve(IBindingContext bindingContext, bool searchInParent, bool includeImplicitBindings)
        {
            return GetInjectorResolver().CanResolve(bindingContext, searchInParent, includeImplicitBindings);
        }

        /// <summary>
        /// Resolve instance for the specified <see cref="IBindingContext"/>.
        /// </summary>
        /// <param name="bindingContext">The specified <see cref="IBindingContext"/>.</param>
        /// <returns>An instance of the service.</returns>
        public object Resolve(IBindingContext bindingContext)
        {
            return GetInjectorResolver().Resolve(bindingContext);
        }

        /// <summary>
        /// Resolves all instances for the specified <see cref="IBindingContext"/>.
        /// </summary>
        /// <param name="bindingContext">The specified <see cref="IBindingContext"/>.</param>
        /// <param name="useParentToResolve">If <c>true</c> also use parent bindings to resolve.</param>
        /// <returns>A series of instances of the service.</returns>
        public IList<object> ResolveAll(IBindingContext bindingContext, bool useParentToResolve)
        {
            return GetInjectorResolver().ResolveAll(bindingContext, useParentToResolve);
        }


        /// <summary>
        /// Resolves all instances for the specified service <see cref="System.Type"/>.
        /// </summary>
        /// <param name="service">Service for resolve.</param>
        /// <param name="parameters">Parameters for service.</param>
        /// <param name="specialParameters">Special parameters for resolve specified service.</param>
        /// <param name="useParentToResolve">If <c>true</c> also use parent bindings to resolve.</param>
        /// <returns>A series of instances of the service.</returns>
        public IList<object> ResolveAll(Type service, IEnumerable<IInjectionParameter> parameters, IDictionary<string, object> specialParameters, bool useParentToResolve)
        {
            return GetInjectorResolver().ResolveAll(service, parameters, specialParameters, useParentToResolve);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Get <see cref="IInjectorResolver"/> for <see cref="MugenInjectionServiceBase"/>.
        /// </summary>
        /// <returns></returns>
        protected virtual IInjectorResolver GetInjectorResolver()
        {
            return MugenInjectionHttpApplication.ApplicationConfiguration.Injector;
        }

        #endregion

        #region Implementation of IServiceProvider

        /// <summary>
        /// Gets the service object of the specified type.
        /// </summary>
        /// <returns>
        /// A service object of type <paramref name="serviceType"/>.
        ///                     -or- 
        ///                 null if there is no service object of type <paramref name="serviceType"/>.
        /// </returns>
        /// <param name="serviceType">An object that specifies the type of service object to get. 
        ///                 </param>
        object IServiceProvider.GetService(Type serviceType)
        {
            return GetInjectorResolver().GetService(serviceType);
        }

        #endregion
    }
}